package cate.game.pvp.pointrace.handler;

import cate.common.table.d.GDFight;
import cate.common.table.d.GDFunc;
import cate.game.GameBody;
import cate.game.event.pointrace.PointRaceRwdEvent;
import cate.game.event.pointrace.PointRaceTimerEvent;
import cate.game.framework.common.compress.PlaySideCompressHelper;
import cate.game.log.GameLoggerFactory;
import cate.game.play.part.FightSide;
import cate.game.play.part.PlaySide;
import cate.game.play.proce.play.PlayPO;
import cate.game.pvp.pointrace.PointRaceDataManager;
import cate.game.pvp.pointrace.data.PointRaceOpponent;
import cate.game.pvp.pointrace.data.PointRacePs;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.fight.FuncPosition;
import cate.game.role.pvp.pointrace.PointRaceFTC;
import cate.game.role.pvp.pointrace.msg.PointRaceGetPsReq;
import cate.game.role.pvp.pointrace.msg.PointRaceGetPsResp;
import easy.java.practice.errorcode.EcResult;
import lombok.Getter;
import org.slf4j.Logger;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;


@Getter
public abstract class PointRaceHandler
        implements PointRaceRankHandler,
        PointRaceTimerEvent.Handler,
        PointRaceRwdEvent.Handler {

    private final PointRaceDataManager manager;
    private final GameBody gameBody;
    protected final Logger log;

    public static LocalPointRaceHandler ofLocal(GameBody gameBody, PointRaceDataManager manager) {
        return new LocalPointRaceHandler(
                gameBody,
                manager,
                manager.getOpQuery(),
                manager.getPsOperation(),
                manager.getChallenge(),
                manager.getRankHandler(),
                manager.getRankRwdOperation());
    }

    public PointRaceHandler(GameBody gameBody, PointRaceDataManager manager) {
        this.gameBody = Objects.requireNonNull(gameBody);
        this.manager = Objects.requireNonNull(manager);
        this.log = GameLoggerFactory.getLogger(gameBody, getClass());
    }

    public abstract EcResult<List<PointRaceOpponent>> findOpponents(Role role);

    protected abstract PointRacePs findPs(String oppUid);

    public abstract int findRank(Role role);

    public abstract int findRank(String roleUid);

    public abstract void updatePosition(Role role, FuncPosition funcPosition);

    public abstract void whenChallengeWin(PointRaceOpponent oppA, PointRacePs psB, PlayPO playPO);

    public abstract void syncRolePoints(Role role);

    public EcResult<Void> challenge(Role role, String oppUid, boolean skip) {
        StopWatch stopWatch = new StopWatch();
        EcResult<Void> r = challengeCheck(role, oppUid, skip);
        if (!r.ok()) {
            return r;
        }
        final PointRacePs opPs = findPs(oppUid);

        if (Objects.isNull(opPs)) {
            return r.fail("获取对手信息失败,请刷新一下对手");
        }

        PlaySide playSide;

        stopWatch.start("t1");
        EcResult<PlaySide> psEc = PlaySideCompressHelper.uncompressEc(opPs.getCps());
        stopWatch.stop();
        log.info("解压对手阵容消耗时间 {} ms", stopWatch.getLastTaskTimeMillis());
        if (!psEc.ok()) {
            return r.fail("解压玩家阵容错误");
        }
        playSide = psEc.data;

        if (opPs.getOpponent().getSnapshot().unreal) {
            opPs.getOpponent().getSnapshot().uid = oppUid;
            playSide.snapshot.uid = oppUid;
        }

        role.getPvp().pointRace.challenge();

        PointRaceFTC ftc = new PointRaceFTC();
        ftc.skip = skip;
        ftc.funcId = GDFunc.POINT_RACE;
        ftc.playStory.params.put("A", findRank(role.getUid()));
        ftc.playStory.params.put("B", findRank(oppUid));
        ftc.setPositionApply(GDFunc.ADVENTURE);
        FightSide fsRes = role.getGame().fight.side.createFightSideByPlaySide(GDFight.Team.B, playSide);
        EcResult<PlayPO> play_r = role.getGame().play.startByRole(role, ftc, fsRes);

        if (!play_r.ok()) {
            return r.fail(play_r.message);
        }

        PlayPO playPO = play_r.data;

        PointRaceOpponent oppRole = PointRaceOpponent.ofCopy(new RoleSnapshot(role), role.getPvp().pointRace.points);

        whenChallengeWin(oppRole, opPs, playPO);

        role.getPvp().pointRaceMark.updateMark(playPO.winner == GDFight.Team.A, playPO);

        role.getPvp().pointRace.fighting = true;
        role.getHistory().action.pointRace();
        role.getTrace().challengePointRace();

        return r;
    }

    protected EcResult<Void> challengeCheck(Role role, String oppUid, boolean skip) {
        return role.getPvp().pointRace.challengeCheck(oppUid, skip);
    }

    public long getSeasonStartTime() {
        return manager.getData().getOpenTime();
    }

    public int getSeason() {
        return manager.getData().getSeason();
    }

    public EcResult<PointRaceGetPsResp> handleGetPsReq(Role role, PointRaceGetPsReq req) {
        EcResult<PointRaceGetPsResp> r = new EcResult<>();
        if (!StringUtils.hasLength(req.uid)) {
            return r.fail("参数有误!");
        }
        List<PointRaceOpponent> opponents = role.getPvp().pointRace.opponents;
        if (Objects.isNull(opponents) || opponents.isEmpty()) {
            return r.fail("请重新刷新对手!");
        }

        PointRaceOpponent opponent = opponents.stream()
                .filter(op -> req.uid.equalsIgnoreCase(op.getSnapshot().uid))
                .findAny()
                .orElse(null);

        if (Objects.isNull(opponent)) {
            return r.fail("请重新刷新对手!");
        }

        return r.success();
    }


}
